﻿using System;
using System.Collections.Generic;
using System.Data.Entity.Infrastructure;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MusicExplorer.Data;

namespace MusicExplorer.WebRepository.Service
{
    public static class ServiceWebRepository
    {
        #region HELPER

        public static List<WEB_REPOSITORY> GetAllWebRepositoryWithoutType()
        {
            MusicExplorerEntities container = new MusicExplorerEntities();
            var repos = container.WEB_REPOSITORY.Where(w => w.type_web_repo_id == null);
            foreach (var repo in repos)
                ((IObjectContextAdapter)container).ObjectContext.Detach(repo);
            var web_repositories = new List<WEB_REPOSITORY>();
            web_repositories = repos.ToList();
            container.Dispose();
            return web_repositories;
        }

        public static List<REF_TYPE_WEB_REPOSITORY> GetAllWebRepositoryTypesWithRepo()
        {
            MusicExplorerEntities container = new MusicExplorerEntities();
            var groups = container.REF_TYPE_WEB_REPOSITORY.Include("WEB_REPOSITORY");
            foreach (var group in groups)
                ((IObjectContextAdapter)container).ObjectContext.Detach(group);
            var type_web_repositories = new List<REF_TYPE_WEB_REPOSITORY>();
            type_web_repositories = groups.ToList();
            container.Dispose();
            return type_web_repositories;
        }

        #region TRACKS
        public static void SetTrackIsRead(TRACK track)
        {
            MusicExplorerEntities container = new MusicExplorerEntities();
            var t = container.TRACK.First(_t => _t.track_key == track.track_key && _t.web_repo_id == track.web_repo_id && _t.group_key == track.group_key);
            t.track_is_read = true;
            container.SaveChanges();
            container.Dispose();
        }

        public static void SetTrackIsFavorite(TRACK track)
        {
            MusicExplorerEntities container = new MusicExplorerEntities();
            var t = container.TRACK.First(_t => _t.track_key == track.track_key && _t.web_repo_id == track.web_repo_id && _t.group_key == track.group_key);
            t.track_is_favorite = !t.track_is_favorite;
            container.SaveChanges();
            container.Dispose();
        }

        public static List<TRACK> GetFavoriteTracks()
        {
            MusicExplorerEntities container = new MusicExplorerEntities();
            container.Configuration.LazyLoadingEnabled = false;
            var entities = container.TRACK.Where(t => t.track_is_favorite);
            foreach (var track in entities)
            {
                var joins = container.JN_ARTIST_TRACK.Include("REF_TYPE_ARTIST").Include("ARTIST").Where(j => j.track_key == track.track_key && j.web_repo_id == track.web_repo_id);
                foreach (var join in joins) track.JN_ARTIST_TRACK.Add(join);
            }
            var tracks = entities.ToList();
            container.Dispose();
            return tracks;
        }
        #endregion

        #region PREFERENCES
        public static List<GROUP> GetGroupsFromWebRepository(WEB_REPOSITORY repo)
        {
            MusicExplorerEntities container = new MusicExplorerEntities();
            var entities = container.GROUP.Where(gwr => gwr.web_repo_id == repo.web_repo_id);
            foreach (var group in entities)
                ((IObjectContextAdapter)container).ObjectContext.Detach(group);
            var genres = new List<GROUP>();
            genres = entities.ToList();
            container.Dispose();
            return genres;
        }

        public static List<ARTIST> GetRegisteredArtistsFromWebRepository(WEB_REPOSITORY repo)
        {
            MusicExplorerEntities container = new MusicExplorerEntities();
            var entities = container.ARTIST.Where(awr => awr.web_repo_id == repo.web_repo_id && awr.is_registered);
            foreach (var artist in entities)
                ((IObjectContextAdapter)container).ObjectContext.Detach(artist);
            var artists = new List<ARTIST>();
            artists = entities.ToList();
            container.Dispose();
            return artists;
        }

        public static List<WEB_REPOSITORY> GetWebRepositoriesFromType(REF_TYPE_WEB_REPOSITORY typeWebRepository)
        {
            MusicExplorerEntities container = new MusicExplorerEntities();
            var entities = container.WEB_REPOSITORY.Where(wr => wr.type_web_repo_id == typeWebRepository.type_web_repo_id);
            foreach (var repo in entities)
                ((IObjectContextAdapter)container).ObjectContext.Detach(repo);
            var repos = new List<WEB_REPOSITORY>();
            repos = entities.ToList();
            container.Dispose();
            return repos;
        }

        public static void SaveGroupPreferences(WEB_REPOSITORY repo, IEnumerable<GROUP> groups)
        {
            MusicExplorerEntities container = new MusicExplorerEntities();
            var entities = container.GROUP.Where(gwr => gwr.web_repo_id == repo.web_repo_id);
            foreach (var group in entities)
            {
                var newGroup = groups.FirstOrDefault(g => g.group_key == group.group_key);
                if (newGroup != null)
                {
                    group.group_order = newGroup.group_order;
                    group.group_visibility = newGroup.group_visibility;
                }
            }
            container.SaveChanges();
            container.Dispose();
        }

        public static void SaveArtistPreferences(WEB_REPOSITORY repo, IEnumerable<ARTIST> artists)
        {
            MusicExplorerEntities container = new MusicExplorerEntities();
            var entities = container.ARTIST.Where(awr => awr.web_repo_id == repo.web_repo_id && awr.is_registered);
            foreach (var artist in entities)
            {
                var newArtist = artists.FirstOrDefault(a => a.artist_key == artist.artist_key);
                if (newArtist != null)
                {
                    artist.artist_order = newArtist.artist_order;
                    artist.artist_visibility = newArtist.artist_visibility;
                }

                // Suppression
                else
                {
                    artist.is_registered = false;
                }
            }

            // Nouveaux artistes
            foreach (var artist in artists)
            {
                if (entities.Count(a => a.artist_key == artist.artist_key) == 0) InsertOrUpdateArtist(artist);
            }

            container.SaveChanges();
            container.Dispose();
        }

        public static void SaveWebRepositoriesPreferences(REF_TYPE_WEB_REPOSITORY type_web_repository, IEnumerable<WEB_REPOSITORY> webRepositories)
        {
            MusicExplorerEntities container = new MusicExplorerEntities();
            var entities = container.WEB_REPOSITORY.Where(wr => wr.type_web_repo_id == type_web_repository.type_web_repo_id);
            foreach (var repo in entities)
            {
                var newRepo = webRepositories.FirstOrDefault(wr => wr.web_repo_key == repo.web_repo_key);
                if (newRepo != null)
                {
                    repo.web_repo_order = newRepo.web_repo_order;
                    repo.web_repo_visibility = newRepo.web_repo_visibility;
                }

                // Suppression
                else
                {
                    ((IObjectContextAdapter)container).ObjectContext.DeleteObject(repo);
                }
            }

            // Nouveaux repo
            foreach (var repo in webRepositories)
            {
                if (entities.Count(w => w.web_repo_key == repo.web_repo_key) == 0) CreateWebRepository(repo);
            }

            container.SaveChanges();
            container.Dispose();
        }
        #endregion

        #endregion

        #region COMMON

        public static async Task<string> GetUrlDataAsync(WebClient webClient, string url)
        {
            if (webClient != null)
                return await webClient.DownloadStringTaskAsync(new Uri(url));
            else
                using (WebClient wc = new WebClient())
                    return await wc.DownloadStringTaskAsync(new Uri(url));
        }

        internal static string GetUrlData(WebClient webClient, string url)
        {
            return new WebClient().DownloadString(new Uri(url));
        }

        internal static async Task<string> GetLocalDataAsync(string path)
        {
            StreamReader reader = new StreamReader(path);
            string text = await reader.ReadToEndAsync();
            reader.Close();
            return text;
        }

        internal static string GetLocalData(string path)
        {
            StreamReader reader = new StreamReader(path);
            string text = reader.ReadToEnd();
            reader.Close();
            return text;
        }

        #endregion

        #region WEB_REPOSITORY

        internal static void CreateWebRepository(WEB_REPOSITORY webRepo)
        {
            MusicExplorerEntities container = new MusicExplorerEntities();
            var entity = container.WEB_REPOSITORY.FirstOrDefault(wp => wp.web_repo_key == webRepo.web_repo_key);
            if (entity == null)
            {
                var type = container.REF_TYPE_WEB_REPOSITORY.First(r => r.type_web_repo_id == webRepo.type_web_repo_id);
                webRepo.REF_TYPE_WEB_REPOSITORY = type;
                container.WEB_REPOSITORY.Add(webRepo);
                container.SaveChanges();
                ((IObjectContextAdapter)container).ObjectContext.Detach(webRepo);
            }
        }

        internal static WEB_REPOSITORY GetYoutubeWebRepository(string channelId)
        {
            MusicExplorerEntities container = new MusicExplorerEntities();
            var idYoutube = GetTypeWebRepository(TypeWebRepository.YoutubeChannel).type_web_repo_id;
            var entity = container.WEB_REPOSITORY.Include("REF_TYPE_WEB_REPOSITORY").FirstOrDefault(wp => wp.web_repo_key == channelId && wp.type_web_repo_id == idYoutube);
            ((IObjectContextAdapter)container).ObjectContext.Detach(entity);
            container.Dispose();
            return entity;
        }

        internal static WEB_REPOSITORY GetSoundcloudWebRepository(string userId)
        {
            MusicExplorerEntities container = new MusicExplorerEntities();
            var idSoundcloud = GetTypeWebRepository(TypeWebRepository.SoundcloudAccount).type_web_repo_id;
            var entity = container.WEB_REPOSITORY.Include("REF_TYPE_WEB_REPOSITORY").FirstOrDefault(wp => wp.web_repo_key == userId && wp.type_web_repo_id == idSoundcloud);
            ((IObjectContextAdapter)container).ObjectContext.Detach(entity);
            container.Dispose();
            return entity;
        }

        internal static WEB_REPOSITORY GetWebRepository(REF_TYPE_WEB_REPOSITORY type, string repositoryName)
        {
            MusicExplorerEntities container = new MusicExplorerEntities();
            WEB_REPOSITORY repo;
            if(type != null)
                repo = container.WEB_REPOSITORY.Include("REF_TYPE_WEB_REPOSITORY").FirstOrDefault(wp => wp.web_repo_key == repositoryName && wp.type_web_repo_id == type.type_web_repo_id);
            else
                repo = container.WEB_REPOSITORY.Include("REF_TYPE_WEB_REPOSITORY").FirstOrDefault(wp => wp.web_repo_key == repositoryName && wp.type_web_repo_id == null);
            ((IObjectContextAdapter)container).ObjectContext.Detach(repo);
            container.Dispose();
            return repo;
        }

        public static REF_TYPE_WEB_REPOSITORY GetTypeWebRepository(TypeWebRepository type)
        {
            MusicExplorerEntities container = new MusicExplorerEntities();
            var typeStr = type.ToString();
            var typeRepo = container.REF_TYPE_WEB_REPOSITORY.FirstOrDefault(twr => twr.type_web_repo_key == typeStr);
            container.Dispose();
            return typeRepo;
        }

        public static TypeWebRepository GetTypeWebRepositoryFromTrack(TRACK track)
        {
            MusicExplorerEntities container = new MusicExplorerEntities();
            var type = container.WEB_REPOSITORY.First(wp => wp.web_repo_id == track.web_repo_id).REF_TYPE_WEB_REPOSITORY;
            switch (type.type_web_repo_key)
            {
                case ("WebsiteDatabase"): return TypeWebRepository.WebsiteDatabase;
                case ("MusicStore"): return TypeWebRepository.MusicStore;
                case ("YoutubeChannel"): return TypeWebRepository.YoutubeChannel;
                case ("SoundcloudAccount"): return TypeWebRepository.SoundcloudAccount;
                default: return TypeWebRepository.MusicStore;
            }
        }

        private static int GetMaxWebRepositoryOrder(REF_TYPE_WEB_REPOSITORY type)
        {
            var container = new MusicExplorerEntities();
            var webRepositories = container.WEB_REPOSITORY.Where(wr => wr.type_web_repo_id == type.type_web_repo_id);
            if (webRepositories.Count() > 0)
                return webRepositories.Max(wr => wr.web_repo_order);
            else return 0;
        }
        #endregion

        #region GROUPS

        internal static GROUP InsertOrUpdateGroup(GROUP newGroup)
        {
            MusicExplorerEntities container = new MusicExplorerEntities();

            var group = container.GROUP.FirstOrDefault(g => g.group_key == newGroup.group_key && g.web_repo_id == newGroup.web_repo_id);

            if (group == null)
            {
                var repo = container.WEB_REPOSITORY.First(wp => wp.web_repo_id == newGroup.web_repo_id);
                newGroup.group_order = GetMaxGroupOrder(repo) + 1;
                newGroup.group_visibility = true;
                container.GROUP.Add(newGroup);
                container.SaveChanges();
                group = newGroup;
            }
            else
            {
                group.group_name = newGroup.group_name;
                container.SaveChanges();
                ((IObjectContextAdapter)container).ObjectContext.Detach(group);
            }
            
            container.Dispose();
            return group;
        }

        private static int GetMaxGroupOrder(WEB_REPOSITORY repo)
        {
            if (repo.GROUP.Count > 0)
                return repo.GROUP.Max(g => g.group_order);
            else return -1;
        }

        #endregion

        #region ARTIST

        internal static ARTIST InsertOrUpdateArtist(ARTIST newArtist)
        {
            MusicExplorerEntities container = new MusicExplorerEntities();

            var artist = container.ARTIST.FirstOrDefault(a => a.artist_key == newArtist.artist_key && a.web_repo_id == newArtist.web_repo_id);

            if (artist == null)
            {
                container.ARTIST.Add(newArtist);
                container.SaveChanges();
                artist = newArtist;
            }
            else
            {
                artist.artist_name = newArtist.artist_name;
                container.SaveChanges();
                ((IObjectContextAdapter)container).ObjectContext.Detach(artist);
            }

            container.Dispose();
            return artist;
        }

        internal static REF_TYPE_ARTIST GetRefTypeArtist(TypeArtist type)
        {
            MusicExplorerEntities container = new MusicExplorerEntities();
            var typeStr = type.ToString();
            var refTypeArtist = container.REF_TYPE_ARTIST.FirstOrDefault(ta => ta.type_artist_libelle == typeStr);
            container.Dispose();
            return refTypeArtist;
        }

        #endregion

        #region TRACK

        internal static TRACK InsertOrUpdateTrack(TRACK newTrack)
        {
            MusicExplorerEntities container = new MusicExplorerEntities();

            var track = container.TRACK.FirstOrDefault(t => t.track_key == newTrack.track_key && t.web_repo_id == newTrack.web_repo_id);

            if (track == null)
            {
                container.TRACK.Add(newTrack);
                container.SaveChanges();
                track = newTrack;
            }
            else
            {
                track.track_img_url = newTrack.track_img_url;
                track.track_mp3_url = newTrack.track_mp3_url;
                track.track_name = newTrack.track_name;
                track.group_key = newTrack.group_key;
                track.track_publish_date = newTrack.track_publish_date;
                track.track_duration = newTrack.track_duration;
                container.SaveChanges();
                ((IObjectContextAdapter)container).ObjectContext.Detach(track);
            }
            
            container.Dispose();
            return track;
        }

        #endregion

        #region JN_ARTIST_TRACK

        internal static JN_ARTIST_TRACK InsertJnArtistTrack(JN_ARTIST_TRACK newJnArtistTrack)
        {
            MusicExplorerEntities container = new MusicExplorerEntities();

            var jn_artist_track = container.JN_ARTIST_TRACK.FirstOrDefault(t =>
                t.track_key == newJnArtistTrack.track_key &&
                t.web_repo_id == newJnArtistTrack.web_repo_id &&
                t.artist_key == newJnArtistTrack.artist_key);

            if (jn_artist_track == null)
            {
                container.JN_ARTIST_TRACK.Add(newJnArtistTrack);
                container.SaveChanges();
                jn_artist_track = newJnArtistTrack;
            }

            container.Dispose();
            return jn_artist_track;
        }

        #endregion
    }
}
